package optiondef

import (
	"context"
	"fmt"

	"photowall/pkg/config"
	"photowall/pkg/log"
	"sync"

	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

// description: 获取链接微信数据库的 db 指针, 该函数实现使用单例模式
// return {*sqlx.DB}
var (
	mongodbConnSyncOnce sync.Once
	mongodbClient       *mongo.Client
)

func init() {
	// 获取数据库提前获知错误
	getWechatUserCollectionInMongodb()
	log.GetMainLogger().Info(`database service start normal!`)
}

func getMongodbClient() *mongo.Client {
	mongodbConnSyncOnce.Do(func() {
		// 设置客户端连接配置
		clientOptions := options.Client().ApplyURI(config.GetConfig().WechatUserConfig.DbUrl)

		// 连接到MongoDB
		client, err := mongo.Connect(context.TODO(), clientOptions)
		if err != nil {
			log.GetMainLogger().Error(err.Error())
			panic(err)
		}

		// 检查连接
		err = client.Ping(context.TODO(), nil)
		if err != nil {
			log.GetMainLogger().Error(err.Error())
		}

		log.GetMainLogger().Info("Connected to MongoDB!")
		mongodbClient = client
	})

	return mongodbClient
}

func getWechatUserCollectionInMongodb() *mongo.Collection {
	dbName := config.GetConfig().WechatUserConfig.DbName
	collectionName := config.GetConfig().WechatUserConfig.WxUserDbConllection

	// 检查数据库名称和集合名称是否为空
	if dbName == "" {
		log.GetDatabaseLogger().Error("Database name is empty")
		panic(`Database name is empty`)
	}
	if collectionName == "" {
		log.GetDatabaseLogger().Error("Collection name is empty")
		panic(`Collection name is empty`)
	}

	return getMongodbClient().Database(dbName).Collection(collectionName)
}

func addWechatUserInMongodb(userinfo *WxUserInfo) (bool, error) {
	_, err := getWechatUserCollectionInMongodb().InsertOne(context.Background(), userinfo)
	if err != nil {
		log.GetDatabaseLogger().Error(fmt.Sprintf("can not insert db, %v, err: %v", *userinfo, err.Error()))
		return false, err
	}

	return true, nil
}

func deleteWechatUserInMongodb(openid string) (bool, error) {
	res, err := getWechatUserCollectionInMongodb().DeleteOne(context.Background(), bson.M{"OpenID": openid})
	if err != nil {
		log.GetDatabaseLogger().Error(fmt.Sprintf("can not delect user in db, %v, err:%v", openid, err.Error()))
		return false, err
	}

	if res.DeletedCount == 0 {
		return false, nil
	}

	return true, nil
}

func updateWechatUserInMongodb(userinfo *WxUserInfo) (bool, error) {
	filter := bson.M{"OpenID": userinfo.OpenID}

	// 编码为BSON
	bsonData, err := bson.Marshal(*userinfo)
	if err != nil {
		log.GetDatabaseLogger().Error(fmt.Sprintf("can not Decode this struct with bson, %v, err:%v", *userinfo, err))
		return false, err
	}
	update := bson.M{"$set": bsonData}

	res, err := getWechatUserCollectionInMongodb().UpdateOne(context.Background(), filter, update)
	if err != nil {
		log.GetDatabaseLogger().Error(fmt.Sprintf("can not delect user in db, %v, err:%v", *userinfo, err.Error()))
		return false, err
	}

	if res.MatchedCount == 0 {
		return false, nil
	}

	return true, nil
}

func getWechatUserByOpenIDInMongodb(openid string) (*WxUserInfo, error) {
	var res WxUserInfo
	err := getWechatUserCollectionInMongodb().FindOne(context.Background(), bson.M{"open_id": openid}).Decode(&res)
	if err != nil {
		if err == mongo.ErrNoDocuments {
			return nil, nil
		}
		log.GetDatabaseLogger().Error(fmt.Sprintf("can not exec FindOne option, %v, err:%v", openid, err.Error()))
		return nil, err
	}

	return &res, nil
}

// func checkWechatUserByOpenIDInMongodb(openid string) (*UserDbInfo, error) {
// 	var res UserDbInfo
// 	err := getWechatUserCollectionInMongodb().Indexes(context.Background(), bson.M{"OpenID": openid}).Decode(&res)
// 	if err != nil {
// 		log.GetDatabaseLogger().Error(fmt.Sprintf("can not exec findone option, %v", openid), err)
// 		return nil, err
// 	}

// 	return &res, nil
// }
